package com.cardone.validator;

import com.cardone.common.function.*;
import com.cardone.common.util.*;
import com.cardone.context.*;
import com.google.common.collect.*;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.*;
import org.apache.commons.lang3.StringUtils;

import java.util.*;

/**
 * Created by Administrator on 2014/10/30.
 */
public class DefaultValidator implements Validator {
    @Override
    public java.util.Map<String, String> validate(Object obj, String id) {
        return validate(obj, id, true);
    }

    @Override
    public Map<String, String> validate(Object obj, String id, boolean oneError) {
        ValidatorRuleConfig validatorRuleConfig = ContextHolder.getBean(ValidatorRuleConfig.class, id);

        if (validatorRuleConfig == null) {
            throw new IllegalArgumentException(id + "没有定义");
        }

        return validate(obj, validatorRuleConfig, oneError);
    }

    @Override
    public Map<String, String> validate(Object obj, ValidatorRuleConfig validatorRuleConfig) {
        return validate(obj, validatorRuleConfig, true);
    }

    @Override
    public Map<String, String> validate(Object obj, ValidatorRuleConfig validatorRuleConfig, boolean oneError) {
        Map<String, String> errorMap = Maps.newHashMap();

        return validate(errorMap, obj, validatorRuleConfig, null, oneError);
    }

    @Override
    public void validateThrowException(Object obj, String id) {
        validateThrowException(obj, id, true);
    }

    @Override
    public void validateThrowException(Object obj, ValidatorRuleConfig validatorRuleConfig) {
        validateThrowException(obj, validatorRuleConfig, true);
    }

    @Override
    public void validateThrowException(Object obj, String id, boolean oneError) {
        ValidatorRuleConfig validatorRuleConfig = ContextHolder.getBean(ValidatorRuleConfig.class, id);

        if (validatorRuleConfig == null) {
            throw new IllegalArgumentException(id + "没有定义");
        }

        validateThrowException(obj, validatorRuleConfig, oneError);
    }

    @Override
    public void validateThrowException(Object obj, ValidatorRuleConfig validatorRuleConfig, boolean oneError) {
        java.util.Map<String, String> errorMap = this.validate(obj, validatorRuleConfig, oneError);

        if (org.apache.commons.collections.MapUtils.isEmpty(errorMap)) {
            return;
        }

        throw new DictionaryException(MapperUtils.toJson(errorMap)).setErrors(errorMap);
    }

    private Map<String, String> validate(Map<String, String> errorMap, Object obj, ValidatorRuleConfig validatorRuleConfig, String parentName, boolean oneError) {
        if (CollectionUtils.isEmpty(validatorRuleConfig.getValidatorRuleList())) {
            return errorMap;
        }

        String key;

        if (StringUtils.isNotBlank(parentName)) {
            key = parentName + "." + validatorRuleConfig.getName();
        } else {
            key = validatorRuleConfig.getName();
        }

        validator(errorMap, obj, validatorRuleConfig, key);

        if (oneError && MapUtils.isNotEmpty(errorMap)) {
            return errorMap;
        }

        if (CollectionUtils.isNotEmpty(validatorRuleConfig.getChildren())) {
            Map<String, Object> objMap = getStringObjectMap(obj);

            for (ValidatorRuleConfig childrenValidatorRuleConfig : validatorRuleConfig.getChildren()) {
                Object childrenValue = MapUtils.getObject(objMap, childrenValidatorRuleConfig.getName());

                validate(errorMap, childrenValue, childrenValidatorRuleConfig, key, oneError);
            }
        }

        return errorMap;
    }

    private void validator(Map<String, String> errorMap, Object obj, ValidatorRuleConfig validatorRuleConfig, String key) {
        for (ValidatorRule validatorRule : validatorRuleConfig.getValidatorRuleList()) {
            if (!validatorRule.validate(obj)) {
                if (StringUtils.isAnyBlank(validatorRule.getTypeCode(), validatorRule.getCode())) {
                    errorMap.put(key, validatorRule.getMessage());

                    return;
                }

                final ReadDictionaryValueByTypeCodeAndCodeFunction readDictionaryValueByTypeCodeAndCodeFunction = ContextHolder.getBean(ReadDictionaryValueByTypeCodeAndCodeFunction.class);

                if (readDictionaryValueByTypeCodeAndCodeFunction == null) {
                    errorMap.put(key, validatorRule.getMessage());

                    return;
                }

                String message = readDictionaryValueByTypeCodeAndCodeFunction.execution(validatorRule.getMessage(), validatorRule.getTypeCode(), validatorRule.getCode());

                errorMap.put(key, message);

                return;
            }
        }
    }

    private Map<String, Object> getStringObjectMap(Object obj) {
        Map<String, Object> objMap;

        if (obj instanceof Map) {
            objMap = (Map<String, Object>) obj;
        } else {
            String json;

            if (obj instanceof String) {
                json = (String) obj;
            } else {
                json = MapperUtils.toJson(obj);
            }

            objMap = MapperUtils.getMapForJson(json);
        }
        return objMap;
    }
}
